﻿#region
using System;
using System.Collections.Concurrent;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using GFCTP;
using WeifenLuo.WinFormsUI.Docking;

#endregion

namespace GFTradePlat
{
	public partial class FormWorkSpace : DockContent // DockDotNET.DockWindow
	{
		private readonly ConcurrentDictionary<Data, string> _dataID = new ConcurrentDictionary<Data, string>();
		private readonly ConcurrentDictionary<Data, int> _dataShown = new ConcurrentDictionary<Data, int>();
		private readonly ConcurrentDictionary<OrderItem, int> _openLotsLeft = new ConcurrentDictionary<OrderItem, int>();
		//显示策略信号时用
		private readonly ConcurrentDictionary<StrategyData, int> _straDataShown = new ConcurrentDictionary<StrategyData, int>();
		//显示策略信号时用
		private readonly ConcurrentDictionary<Strategy, string> _strategyPropertyValue = new ConcurrentDictionary<Strategy, string>();
		internal WorkSpace ws = null;

		public FormWorkSpace()
		{
			this.InitializeComponent();
			//this.DockType = DockDotNET.DockContainerType.Document;
			DoubleBuffered = true;
			this.chartDB1.Init();
		}

		//显示策略信号时用

		private void timer1_Tick(object sender, EventArgs e)
		{
			#region 刷新K线数据&交易信号显示
			//Data重新配置过参数
			bool dataModified = false;
			foreach (var v in this._dataID)
			{
				if (!v.Key.ToString().Equals(v.Value))
				{
					dataModified = true;
					//foreach(Series s in this.chartDB1.Series.Where(n=>n.ChartArea == this.chartDB1.ChartAreas[ws.Datas.IndexOf(v.Key)].Name))
					this.chartDB1.Series[0].Points.Clear();
					this._dataShown[v.Key] = 0;
				}
			}
			if (this.ws == null)
			{
				return;
			}
			//显示K线
			foreach (var data in this.ws.Datas)
			{
				if (this.ws.Datas.IndexOf(data) > 0)
				{
					break; ///////////// 仅支持 单数据
				}
				int shown = 0;
				shown = this._dataShown.GetOrAdd(data, 0);
				//if(_dataID.TryAdd(data, data.ToString()))
				this._dataID.AddOrUpdate(data, data.ToString(), (k, value) => data.ToString());
				//更新
				if (shown != 0 && shown == data.Bars.Count)
				{
					Bar bar = data.Bars[shown - 1];
					this.chartDB1.Series[0].Points[shown - 1].SetValueY(bar.H, bar.L, bar.O, bar.C);
					this.chartDB1.ResetAxisY();
					this.chartDB1.Invalidate();
				}
				else
				{
					//刷新K线
					while (shown < data.Bars.Count)
					{
						Bar bar = data.Bars[shown];
						this.chartDB1.Series[0].Points.AddXY(bar.D, bar.H, bar.L, bar.O, bar.C);
						if (shown == 0 || bar.D.Date != data.Bars[shown - 1].D.Date)
						{
							this.chartDB1.Series[0].Points[shown].AxisLabel = bar.D.ToString("MM月dd日");
						}
						this._dataShown[data] = ++shown;
					}
				}
			}
			//数据有变动/策略有变动:所有策略信号清除
			if (dataModified)
			{
				this.chartDB1.Annotations.Clear();
				this._strategyPropertyValue.Clear();
				this._straDataShown.Clear();
				this._openLotsLeft.Clear();
			}
			else
			{
				//清除已过时的交易信号:1.
				foreach (var stra in this.ws.Strategies)
				{
					//无参:不处理
					if (stra.ToString().IndexOf('(') < 0)
					{
						continue;
					}
					//参数是有变动:删除对应信号
					string ps = string.Empty;
					if (this._strategyPropertyValue.TryGetValue(stra, out ps))
					{
						if (!stra.ToString().Split('(', ')')[1].Equals(ps))
						{
							for (int i = 0; i < this.chartDB1.Annotations.Count; ++i)
							{
								if (this.chartDB1.Annotations[i].Tag.Equals(stra))
								{
									this.chartDB1.Annotations.RemoveAt(i);
									--i;
								}
							}
							foreach (var straData in stra.Datas)
							{
								this._straDataShown.AddOrUpdate(straData, 0, (k, v) => 0);
							}
						}
					}
				}
			}
			//有K线数据:显示策略信号
			if (this.ws.Datas.Count(n => n.Bars.Count == 0) == 0)
			{
				foreach (var stra in this.ws.Strategies)
				{
					foreach (var straData in stra.Datas)
					{
						if (stra.Datas.IndexOf(straData) > 0)
						{
							break; //////////// 目前仅支持单数据
						}
						//对应的K线数据
						Data data0 = this.ws.Datas[stra.Datas.IndexOf(straData)];
						int shownStr = this._straDataShown.GetOrAdd(straData, 0);
						while (shownStr < stra.Operations.Count)
						{
							OrderItem order = stra.Operations[shownStr];
							this._straDataShown[straData] = ++shownStr;
							//策略箭头
							ArrowAnnotation arrow = new ArrowAnnotation();
							arrow.AxisX = this.chartDB1.ChartAreas[0].AxisX;
							arrow.AxisY = this.chartDB1.ChartAreas[0].AxisY;
							//arrow.AnchorDataPoint = this.chart1.Series[0].Points.FindByValue(operation.D.ToOADate(), "X");
							arrow.ClipToChartArea = this.chartDB1.ChartAreas[0].Name; //防止线出界
							arrow.ArrowSize = 2; // (int)Math.Ceiling(this.chart1.Width / (this.chart1.ChartAreas[0].AxisX.ScaleView.ViewMaximum - this.chart1.ChartAreas[0].AxisX.ScaleView.ViewMinimum));							//在prepost中进行更改
							arrow.ArrowStyle = ArrowStyle.Simple; //.Tailed;			//双尾箭头
							arrow.LineWidth = 0; //不显示边线
							arrow.BackColor = ((order.Dir == EnumDirectionType.Buy && order.Offset == EnumOffsetType.Open) || (order.Dir == EnumDirectionType.Sell && order.Offset != EnumOffsetType.Open)) ? Color.Red : Color.Blue; //填充颜色
							arrow.IsSizeAlwaysRelative = true; //使用绝对值控制下面的高/宽
							arrow.Width = 0;
							arrow.X = data0.Bars.FindIndex(n => n.D == order.Date) + 1; //坐标是从1开始的
							arrow.ToolTip = stra + ":" + (order.Dir == EnumDirectionType.Buy ? "买" : "卖") + (order.Offset == EnumOffsetType.Open ? "开" : "平") + order.Lots + "@" + order.Price.ToString();
							arrow.Y = order.Price;
							if (order.Dir == EnumDirectionType.Sell)
							{
								arrow.Height = -3; // 6 * priceTick;									//在prepost中进行更改:但要保持符号一致
							}
							else
							{
								arrow.Height = 3; // -6 * priceTick;									//在prepost中进行更改:但要保持符号一致
							}
							arrow.Tag = stra;
							this.chartDB1.Annotations.Add(arrow);
							//画开平连线						
							if (order.Offset == EnumOffsetType.Open)
							{
								this._openLotsLeft.TryAdd(order, order.Lots);
							}
							else
							{
								int lotsClosing = order.Lots;
								for (int j = 0; lotsClosing > 0 && j < shownStr; j++)
								{
									OrderItem open = stra.Operations[j];
									if (open.Offset == EnumOffsetType.Open && open.Dir != order.Dir)
									{
										int lotsLeft = this._openLotsLeft[open];
										if (lotsLeft == 0) //已全部平仓=>再向后递归
										{
											continue;
										}
										//找对应的开仓K线
										LineAnnotation line = new LineAnnotation();
										//修改已平手数
										int volume = Math.Min(lotsLeft, lotsClosing);
										lotsLeft -= volume;
										lotsClosing -= volume;
										int idxOpen = data0.Bars.FindIndex(n => n.D == open.Date);
										int idx = data0.Bars.FindIndex(n => n.D == order.Date);
										line.IsSizeAlwaysRelative = false;
										line.LineDashStyle = ChartDashStyle.Dash;
										line.AxisX = this.chartDB1.ChartAreas[0].AxisX;
										line.AxisY = this.chartDB1.ChartAreas[0].AxisY;
										line.ClipToChartArea = this.chartDB1.ChartAreas[0].Name; //防止线出界
										//line.AnchorDataPoint = this.seriesK.Points[order.BarIndex];
										line.LineWidth = 1;
										line.LineColor = (order.Price - open.Price)*(order.Dir == EnumDirectionType.Sell ? 1 : -1) > 0 ? Color.IndianRed : Color.MediumBlue; //盈利:红,亏损:蓝
										//line.StartCap = LineAnchorCapStyle.None;//.Arrow;
										//line.EndCap = LineAnchorCapStyle.None;//.Arrow;
										line.Width = idx - idxOpen;
										line.X = idxOpen + 1; //坐标是从1开始的
										line.Y = open.Price;
										line.Height = order.Price - open.Price;
										line.Tag = stra;
										this.chartDB1.Annotations.Add(line);
										//更新开仓指令对应的剩余手数
										this._openLotsLeft[open] = lotsLeft;
									}
								}
							}
						}
					}
				}
			}
			#endregion

			//刷新顶端显示
			if (this.ws.Datas.Count > 0 && this.ws.Datas[0].Bars.Count > 0)
			{
				Bar last = this.ws.Datas[0].Bars[this.ws.Datas[0].CurrentBar];
				this.toolStripLabelInstrument.Text = this.ws.Datas[0].Instrument; //此处应在数据加载时赋值
				this.toolStripLabelInterval.Text = this.ws.Datas[0].Interval + " " + this.ws.Datas[0].IntervalType.ToString().Substring(0, 1);
				this.toolStripLabelDT.Text = last.D.ToString("MM.dd HH:mm");
				this.toolStripLabelO.Text = last.O.ToString();
				this.toolStripLabelH.Text = last.H.ToString();
				this.toolStripLabelL.Text = last.L.ToString();
				this.toolStripLabelC.Text = last.C.ToString();
			}
		}

		private void chartDB1_Click(object sender, EventArgs e)
		{
			Activate();
		}

		private void FormWorkSpace_FormClosed(object sender, FormClosedEventArgs e)
		{
		}
	}
}
